The joys of old code
I’ve been playing around with Delphi ever since high school. I took a Pascal programming class and thought it was a really cool language. Shame you couldn’t do visual programming with it, though. (I was really into VB at the time.) Then a buddy of mine introduced me to version 1 of “this new Visual Pascal program” and it was love at first byte. But I didn’t get real serious about Delphi until about three years ago, when I decided to dust off an old pet project of mine from the D7 days, a tool I created for the purpose of making team collaboration easier for RPG Maker 2000 projects.
RPG Maker is a fun system for, well, making console-style RPGs. Problem is, the data file system and its indexing works on the implicit assumption that there’s only one person using it at a time, but it takes a small team to effectively create any game of non-trivial complexity. The team I was on had worked out our own file-locking system based on sending emails to each other, but it was a headache, so I pulled out my copy of Delphi 7 Personal, spent a few weeks studying the file formats in a hex editor, and hacked up a really simple diff/merge tool that created patches to be mailed and re-integrated at the other end. The other guys thought it was the coolest thing ever!
And then real life got in the way for all of us, and it just sorta sat there on my hard drive doing nothing for a few years until I decided it would be fun to build a tool to replace RPG Maker. It’s a really fun system, but it has a very limited feature set and trying to do anything beyond that got very complicated very quickly. I’d been working as a scripter on another project, and I needed to do something that would require function calls and passing data between them, which it doesn’t support. But it does have a global array of integers, and I figured I could set aside a certain number of them as registers, with an understood convention that they were for passing data. I was halfway to implementing a simple assembler on top of RPG Maker’s event system when I came to my senses and realized that what it really needed was a real scripting language with real function calls.
That’s how the “The Ultimate Rpg BUilder” (TURBU) project was born. It was originally conceived as a clone of RPG Maker minus the limitations, particularly the lack of full-featured scripting support. I already had most of the file format worked out; all I needed was to clone the game engine and the editor. I figured it would be a fun way to learn a few things about game programming. In retrospect, that was probably a bit like Tom Sawyer convincing himself it would be fun to paint every fence in town.
The clone engine took me about a year to build, and it kinda-sorta worked, mostly, except when it didn’t. And when it didn’t, it was a big huge mess, but that was OK. I had only meant it as a proof of concept anyway, to learn how things worked so I could get the next one right.
I spent most of the next year setting up infrastructure for the editor, which was going to have its own file formats and data representations because RPG Maker’s weren’t flexible enough. Along the way I got a real job as an “official” Delphi programmer. I showed them some of the code I’d written in the TURBU engine, and the problems I’d had to solve to implement the engine had taken me into enough features of the Delphi language and the RTL and VCL that the interview questions were no trouble at all.
My work on the editor has slowed down a bit since then, what with having a lot less free time and all, but I’ve recently gotten to the point where I have to start building the real TURBU game engine in order to continue my work on the editor. I’ve been going back through the old code to see how I did things before, untangling conceptual snarls and fixing a lot of things as I go. (It’s amazing how much you can learn from a year and a half of working on a real commercial project with a team of other coders!)
Most of the old code’s all right. Some of it’s kinda bad. But then there are the occasional “What was I thinking?!?” moments. (No, not like that.) Like a unit that contains two classes that belong to different conceptual parts of the program, but I had to put them in the same unit because they both reference each other. I looked at it and found that one of the two was composed entirely of methods, with all the real work taking place in a few abstract virtual methods. I almost had it right, but I didn’t know about interfaces when I wrote this unit.
And then I looked around in the code for the other class to see where it actually used this abstract base class, to know what I had to put in the interface. I only found one reference in one place, inside a case block. (FCharacter is the reference to the other class.)
[code lang="Delphi"] $22: begin orphan := FCharacter; FCharacter.changeSprite(FOrder.name, FOrder.data[1]); self := orphan.base; end; [/code]
There’s a character object that holds a sprite object, which describes how it looks on screen. This is supposed to change the character’s sprite, from within the sprite’s code. But that last line… this was a couple years before I knew how assignment to self works, and I really haven’t the slightest idea as to why I wrote that like that or why it never produced strange bugs or memory leaks. There are a bunch of strange things in the codebase, but that’s probably the craziest one I’ve come across so far.
Makes me wonder what the code I’m writing now will look like to me in two years…
Nice blogpost, fun and very recognizable to read.
Nice post, thank you for sharing this!
I’ve stopped feeling ashamed of all the – well, sometimes really really really crappy – code I’ve left behind. It’s the proof that shows that we aren’t stalling, but instead constantly improving. I find that edifying.
Cheers!